package com.xc.ezplan.admin.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xc.ezplan.admin.entity.AdminMenu;
import com.xc.ezplan.admin.entity.AdminRolesMenus;
import com.xc.ezplan.admin.entity.AdminUsersRoles;
import com.xc.ezplan.admin.mapper.AdminRolesMenusMapper;
import com.xc.ezplan.admin.mapper.AdminUsersRolesMapper;
import com.xc.ezplan.admin.service.AdminMenuService;
import com.xc.ezplan.admin.mapper.AdminMenuMapper;
import com.xc.ezplan.admin.vo.AdminMenuVo;
import com.xc.ezplan.admin.vo.MenuMetaVo;
import com.xc.ezplan.admin.vo.MenuVo;
import com.xc.ezplan.cache.constants.RedisKey;
import com.xc.ezplan.cache.utils.CacheUtil;
import com.xc.ezplan.core.base.SearchCondition;
import com.xc.ezplan.core.exception.BadRequestException;
import com.xc.ezplan.core.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lixingchen
 * @date 2022/11/19
 * @description 菜单管理实现类
 */
@Service
@Primary
@RequiredArgsConstructor
@CacheConfig(cacheNames = "menu")
public class AdminMenuServiceImpl extends ServiceImpl<AdminMenuMapper, AdminMenu> implements AdminMenuService {

	private final AdminMenuMapper adminMenuMapper;

	private final AdminRolesMenusMapper adminRolesMenusMapper;

	private final AdminUsersRolesMapper adminUsersRolesMapper;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void createMenu(AdminMenuVo adminMenuVo) {
		AdminMenu adminMenu = new AdminMenu();
		BeanUtils.copyProperties(adminMenuVo, adminMenu);
		adminMenuMapper.insert(adminMenu);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteMenu(List<Long> ids) {
		adminMenuMapper.delete(new QueryWrapper<AdminMenu>().lambda().in(AdminMenu::getId, ids));
		adminRolesMenusMapper.delete(new QueryWrapper<AdminRolesMenus>().lambda().in(AdminRolesMenus::getMenuId, ids));
		CacheUtil.deleteCache(RedisKey.MENU_ID, ids);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateMenu(AdminMenuVo adminMenuVo) {
		if (adminMenuVo.getId().equals(adminMenuVo.getPid())) {
			throw new BadRequestException("上级不能为自己");
		}
		AdminMenu adminMenu = new AdminMenu();
		BeanUtils.copyProperties(adminMenuVo, adminMenu);
		adminMenuMapper.update(adminMenu,
				new UpdateWrapper<AdminMenu>().lambda().eq(AdminMenu::getId, adminMenu.getId()));
		CacheUtil.deleteCache(RedisKey.MENU_ID, adminMenuVo.getId());
	}

	@Override
	@Cacheable(key = "'id:' + #p0")
	public Object queryMenu(Long menuId) {
		AdminMenuVo adminMenuVo = new AdminMenuVo();
		LambdaQueryWrapper<AdminMenu> adminMenuLambdaQueryWrapper = new QueryWrapper<AdminMenu>().lambda();
		if (menuId != null) {
			AdminMenu adminMenu = adminMenuMapper.selectById(menuId);
			BeanUtils.copyProperties(adminMenu, adminMenuVo);
			adminMenuLambdaQueryWrapper.ne(AdminMenu::getId, menuId);
		}
		adminMenuVo.setMenuList(adminMenuMapper.selectList(adminMenuLambdaQueryWrapper));
		return adminMenuVo;
	}

	@Override
	public Object buildMenus() {
		// 获取用户ID
		Long userId = StpUtil.getLoginIdAsLong();

		List<AdminMenu> permissionList = new ArrayList<>();
		// 查询用户所有路由权限
		// 老板拥有全部权限
		if (userId.equals(1L)) {
			// 筛选出component非空的菜单
			List<AdminMenu> adminMenus = adminMenuMapper.selectList(null).stream()
					.filter(menu -> StringUtils.isNotBlank(menu.getComponent())).collect(Collectors.toList());
			permissionList.addAll(adminMenus);
		} else {
			List<Long> roleIds = adminUsersRolesMapper
					.selectList(new QueryWrapper<AdminUsersRoles>().lambda().eq(AdminUsersRoles::getUserId, userId))
					.stream().map(AdminUsersRoles::getRoleId).collect(Collectors.toList());
			Set<Long> menuIds = adminRolesMenusMapper
					.selectList(new QueryWrapper<AdminRolesMenus>().lambda().in(AdminRolesMenus::getRoleId, roleIds))
					.stream().map(AdminRolesMenus::getMenuId).collect(Collectors.toSet());
			// 筛选出有权限的且component非空的菜单
			adminMenuMapper.selectList(new QueryWrapper<AdminMenu>().lambda().in(AdminMenu::getId, menuIds)).stream()
					.filter(menu -> StringUtils.isNotBlank(menu.getComponent()))
					.forEach(permissionList::add);
		}

		// 封装成MenuVo
		List<MenuVo> menuVos = new ArrayList<>();
		if (!CollectionUtils.isEmpty(permissionList)){
			permissionList.forEach(
					menu->{
						MenuVo menuVo = new MenuVo();
						BeanUtils.copyProperties(menu,menuVo);
						MenuMetaVo menuMetaVo = new MenuMetaVo(menu.getTitle(), menu.getIcon(), null);
						menuVo.setMeta(menuMetaVo);
						menuVos.add(menuVo);
					}
			);
		}
		// 组成树
		return listWithTree(menuVos);
	}

	@Override
	public Object queryAllMenu(Long pid) {
		return adminMenuMapper.selectList(new QueryWrapper<AdminMenu>().lambda().ne(AdminMenu::getPid, pid));
	}

	@Override
	public Object childMenu(Long id) {
		Set<AdminMenu> menuSet = new HashSet<>();
		// List<MenuDto> menuList = menuService.getMenus(id);
		// menuSet.add(menuService.findOne(id));
		// menuSet = menuService.getChildMenus(menuMapper.toEntity(menuList), menuSet);
		// Set<Long> ids =
		// menuSet.stream().map(Menu::getId).collect(Collectors.toSet());
		return null;
	}

	@Override
	public Object getMenuSuperior(List<Long> ids) {
		return null;
	}

	@Override
	public void exportMenu(HttpServletResponse response, AdminMenuVo adminMenuVo) throws Exception {

	}

	@Override
	public void changeHidden(Long menuId, Boolean hidden) {
		AdminMenu adminMenu = new AdminMenu();
		adminMenu.setHidden(hidden);
		adminMenuMapper.update(adminMenu, new UpdateWrapper<AdminMenu>().lambda().eq(AdminMenu::getId, menuId));
	}

	@Override
	public Object pageQueryMenu(SearchCondition searchCondition, Page<AdminMenu> page) {
		List<Date> createTime = searchCondition.getCreateTime();
		LambdaQueryWrapper<AdminMenu> queryWrapper = new QueryWrapper<AdminMenu>().lambda().like(
				StringUtils.isNotBlank(searchCondition.getKeyWord()), AdminMenu::getTitle,
				searchCondition.getKeyWord());
		if (!CollectionUtils.isEmpty(createTime) && createTime.size() == 2) {
			queryWrapper.between(AdminMenu::getCreateTime, createTime.get(0), createTime.get(1));
		}
		Page<AdminMenu> adminMenuPage = adminMenuMapper.selectPage(page, queryWrapper);
		adminMenuPage.setRecords(listWithTree2(adminMenuPage.getRecords()));
		return adminMenuPage;
	}


	private List<AdminMenu> listWithTree2(List<AdminMenu> list) {
		return list.stream()
				// 2. 找出所有顶级（规定 0 为顶级）
				.filter(o -> Objects.equals(0L, o.getPid()))
				// 3.给当前父级的 childList 设置子
				.peek(o -> o.setChildren(getChildList(o, list)))
				// 4.收集
				.collect(Collectors.toList());
	}

	/**
	 * 根据当前父类 找出子类， 并通过递归找出子类的子类
	 *
	 * @param menuVo:
	 * @param list:
	 * @return : List<AdminDept>
	 */
	private List<AdminMenu> getChildList(AdminMenu menuVo, List<AdminMenu> list) {
		return list.stream()
				// 筛选出父节点id == parentId 的所有对象 => list
				.filter(o -> Objects.equals(menuVo.getId(), o.getPid()))
				.peek(o -> o.setChildren(getChildList(o, list))).collect(Collectors.toList());
	}

	private List<MenuVo> listWithTree(List<MenuVo> list) {
		return list.stream()
				// 2. 找出所有顶级（规定 0 为顶级）
				.filter(o -> Objects.equals(0L, o.getPid()))
				// 3.给当前父级的 childList 设置子
				.peek(o -> o.setChildren(getChildList(o, list)))
				// 4.收集
				.collect(Collectors.toList());
	}

	/**
	 * 根据当前父类 找出子类， 并通过递归找出子类的子类
	 *
	 * @param menuVo:
	 * @param list:
	 * @return : List<AdminDept>
	 */
	private List<MenuVo> getChildList(MenuVo menuVo, List<MenuVo> list) {
		return list.stream()
				// 筛选出父节点id == parentId 的所有对象 => list
				.filter(o -> Objects.equals(menuVo.getId(), o.getPid()))
				.peek(o -> o.setChildren(getChildList(o, list))).collect(Collectors.toList());
	}

}
